/*
 * @lc app=leetcode.cn id=127 lang=cpp
 *
 * [127] 单词接龙
 *
 * https://leetcode.cn/problems/word-ladder/description/
 *
 * algorithms
 * Hard (48.45%)
 * Likes:    1348
 * Dislikes: 0
 * Total Accepted:    206.6K
 * Total Submissions: 425.6K
 * Testcase Example:  '"hit"\n"cog"\n["hot","dot","dog","lot","log","cog"]'
 *
 * 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 ->
 * s2 -> ... -> sk：
 * 
 * 
 * 每一对相邻的单词只差一个字母。
 * 对于 1 <= i <= k 时，每个 si 都在 wordList 中。注意， beginWord 不需要在 wordList 中。
 * sk == endWord
 * 
 * 
 * 给你两个单词 beginWord 和 endWord 和一个字典 wordList ，返回 从 beginWord 到 endWord 的 最短转换序列
 * 中的 单词数目 。如果不存在这样的转换序列，返回 0 。
 * 
 * 
 * 示例 1：
 * 
 * 
 * 输入：beginWord = "hit", endWord = "cog", wordList =
 * ["hot","dot","dog","lot","log","cog"]
 * 输出：5
 * 解释：一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。
 * 
 * 
 * 示例 2：
 * 
 * 
 * 输入：beginWord = "hit", endWord = "cog", wordList =
 * ["hot","dot","dog","lot","log"]
 * 输出：0
 * 解释：endWord "cog" 不在字典中，所以无法进行转换。
 * 
 * 
 * 
 * 提示：
 * 
 * 
 * 1 <= beginWord.length <= 10
 * endWord.length == beginWord.length
 * 1 <= wordList.length <= 5000
 * wordList[i].length == beginWord.length
 * beginWord、endWord 和 wordList[i] 由小写英文字母组成
 * beginWord != endWord
 * wordList 中的所有字符串 互不相同
 * 
 * 
 */

// @lc code=start
class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        std::unordered_set<std::string> wordSet(wordList.begin(), wordList.end());

        if (wordSet.find(endWord) == wordSet.end()) //字典中不存在结尾单词
            return 0;

        //使用广度优先搜索 BFS
        //在搜索的过程中其实就是遍历图的过程, 只不过并没有把图构建出来

        //记录word是否被访问过, 并且记录下路径长
        //由于是 BFS, 一旦访问到结果, 肯定就是最短路径
        std::unordered_map<std::string, int> visitMap;

        std::queue<std::string> nodes;
        nodes.push(beginWord);

        visitMap.insert({beginWord, 1});

        while (!nodes.empty()) {
            auto node = nodes.front();
            nodes.pop();

            int path = visitMap[node];

            //判断是否能够接龙
            for (int i = 0; i < node.size(); i++) {
                for (int j = 0; j < 26; j++) {
                    auto temp = node;
                    temp[i] = 'a' + j;

                    //字典中没有, 或者已经访问过
                    if (wordSet.find(temp) == wordSet.end() || 
                        visitMap.find(temp) != visitMap.end())
                        continue;

                    if (temp == endWord)
                        return path + 1;

                    nodes.push(temp);
                    visitMap.insert({temp, path + 1});
                }
            }
        }

        return 0;
    }
};
// @lc code=end

